JAVA类的符号引用的理解

您所在的位置:网站首页 java 符号引用 直接引用 JAVA类的符号引用的理解

JAVA类的符号引用的理解

2024-07-10 20:54| 来源: 网络整理| 查看: 265

符号引用只是一些符号,包含在字节码文件的常量池中 它主要包括: 在该类中,出现过的各类包,类,接口,字段,方法等元素的全限定名

有java类定义如下:

package Clazz; import java.io.Serializable; /** * @Author : ZGQ * @Date : 2020/3/25 9:56 * @Version : 1.0 */ public class Rookie extends Person implements Serializable { int myFiledCommon; static int myFiledCommonStatic; final static int myFiledCommonStaticFinal = 10086; public void method1(){ int a = 1; int b = 2; int c = a+b; } public void method2(Person person){ System.out.println("THIS person OOPS"); } private void method3(){ } }

编译后,经javap工具反编译,常量池内容如下

Constant pool: #1 = Methodref #6.#32 // Clazz/Person."":()V #2 = Fieldref #33.#34 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #35 // THIS person OOPS #4 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #38 // Clazz/Rookie #6 = Class #39 // Clazz/Person #7 = Class #40 // java/io/Serializable #8 = Utf8 myFiledCommon #9 = Utf8 I #10 = Utf8 myFiledCommonStatic #11 = Utf8 myFiledCommonStaticFinal #12 = Utf8 ConstantValue #13 = Integer 10086 #14 = Utf8 #15 = Utf8 ()V #16 = Utf8 Code #17 = Utf8 LineNumberTable #18 = Utf8 LocalVariableTable #19 = Utf8 this #20 = Utf8 LClazz/Rookie; #21 = Utf8 method1 #22 = Utf8 a #23 = Utf8 b #24 = Utf8 c #25 = Utf8 method2 #26 = Utf8 (LClazz/Person;)V #27 = Utf8 person #28 = Utf8 LClazz/Person; #29 = Utf8 method3 #30 = Utf8 SourceFile #31 = Utf8 Rookie.java #32 = NameAndType #14:#15 // "":()V #33 = Class #41 // java/lang/System #34 = NameAndType #42:#43 // out:Ljava/io/PrintStream; #35 = Utf8 THIS person OOPS #36 = Class #44 // java/io/PrintStream #37 = NameAndType #45:#46 // println:(Ljava/lang/String;)V #38 = Utf8 Clazz/Rookie #39 = Utf8 Clazz/Person #40 = Utf8 java/io/Serializable #41 = Utf8 java/lang/System #42 = Utf8 out #43 = Utf8 Ljava/io/PrintStream; #44 = Utf8 java/io/PrintStream #45 = Utf8 println #46 = Utf8 (Ljava/lang/String;)V

反编译结果中,我们可以看到几个典型的符号引用,比如第一项为实例构造器,第四项为该类方法调用的其他方法,第六项为其父类

#1 = Methodref #6.#32 // Clazz/Person."":()V #4 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/String;)V #6 = Class #39 // Clazz/Person

另外,一个类的生命周期中,共有七个阶段,分别是加载,验证,准备,解析,初始化,使用,卸载

其中,我们主要关心解析过程,因为这个过程的主要工作就是,将符号引用转化为直接引用. 解释直接引用之前,我们要先知道 所谓符号引用,只是一个符号而已,只是告知jvm,此类需要哪些调用方法,引用或者继承哪些类等等信息. 但是JVM在使用这些资源的时候,只有这些符号是不行的,必须详细知道这些资源的地址,才能正确地调用相关资源. 直接引用,就是这样一类指针,它直接指向目标. 解析过程,就是完成将符号引用转化为直接引用的过程,方便后续资源的调用.

JAVA中符号引用的出现是非常自然的,因为在类没有加载的时候,也不能确保其调用的资源被加载,更何况还有可能调用自身的方法或者字段. 就算能确保,其调用的资源也不会每次在程序启动时,都加载在同一个地址. 简而言之,在编译阶段,字节码文件根本不知道这些资源在哪,所以根本没办法使用直接引用,于是只能使用符号引用代替.

然而,这只是解析的一部分,因为加载,验证,准备,解析,初始化这五步操作,实际上是类的初始化,换句话说,根本就没有实例对象产生. 所以,以上内容只对类加载时可以确定的符号引用进行解析,比如父类,接口,静态字段,调用的静态方法等 还有一部分,比如方法中的局部变量,实例字段等,他们什么时候开始解析呢.

很可惜,博主也不是全部知道(希望有一天能够划掉)

1.虚方法 和上方解析不同,上方的解析被称为静态解析 在调用虚方法(JVM中的概念)时,JVM只有运行时才知道此方法指向的地址,所以此时必须用到动态连接,具体的实现方法就是分派 但是实际上,分派又分为静态分派和动态分派,静态分派实际上是属于静态解析的,用于方法的重载. 但是遇到方法重写时,便要用到动态分派了,来确定该虚方法的符号应用究竟是指向哪个地址.

2.静态方法中的非静态变量 3.非静态字段 ....



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3